package top.mcwebsite.playandroid.common.network.impl

import android.Manifest
import android.annotation.SuppressLint
import android.content.Context
import android.content.pm.PackageManager
import android.net.ConnectivityManager
import android.net.Network
import android.net.NetworkCapabilities
import android.net.NetworkRequest
import android.os.Build
import android.util.Log
import androidx.core.content.ContextCompat
import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory
import kotlinx.serialization.json.Json
import okhttp3.Cookie
import okhttp3.HttpUrl
import okhttp3.MediaType
import okhttp3.OkHttpClient
import retrofit2.Retrofit
import top.mcwebsite.playandroid.common.api.AppService
import top.mcwebsite.playandroid.common.network.Constant
import top.mcwebsite.playandroid.common.network.api.NetworkService
import top.mcwebsite.playandroid.common.network.impl.calladapter.ResultCallAdapterFactory
import top.mcwebsite.playandroid.common.network.impl.cookie.PersistentCookieStore
import top.mcwebsite.playandroid.common.network.impl.cookie.PlayAndroidCookieJar
import top.mcwebsite.playandroid.lib.servicemanager.core.ServiceManager
import top.mcwebsite.playandroid.lib.servicemanager.core.annoation.ServiceImpl

@ServiceImpl(NetworkService::class, isSingleton = true)
class NetworkServiceImpl : NetworkService {

    private val retrofit: Retrofit

    private var isNetworkAvailable = false

    private val json = Json {
        ignoreUnknownKeys = true
    }

    init {
        retrofit = Retrofit.Builder()
            .baseUrl(Constant.BASE_URL)
            .addConverterFactory(json.asConverterFactory(MediaType.get("application/json")))
            .addCallAdapterFactory(ResultCallAdapterFactory())
            .client(
                OkHttpClient.Builder()
                    .cookieJar(PlayAndroidCookieJar())
//                    .addInterceptor(ConnectiveInterceptor())
                    .build()
            )
            .build()
    }

    override fun init() {
        registerNetworkCallback()
    }

    override fun <T> createApi(clazz: Class<T>): T {
        return retrofit.create(clazz)
    }

    override fun getCookies(): List<Cookie> {
        return PersistentCookieStore.get(HttpUrl.parse(Constant.BASE_URL)!!)
    }

    override fun clearCookies() {
        PersistentCookieStore.clear()
    }

    private fun registerNetworkCallback() {
        val context = ServiceManager.getService<AppService>().getApplication().applicationContext
        if (ContextCompat.checkSelfPermission(
                context,
                Manifest.permission.ACCESS_NETWORK_STATE
            ) == PackageManager.PERMISSION_GRANTED
        ) {
            val connectivityManager =
                ServiceManager.getService<AppService>().getApplication()
                    .getSystemService(Context.CONNECTIVITY_SERVICE) as? ConnectivityManager
            if (connectivityManager != null) {
                val callback = object : ConnectivityManager.NetworkCallback() {
                    override fun onCapabilitiesChanged(network: Network, networkCapabilities: NetworkCapabilities) {
                        super.onCapabilitiesChanged(network, networkCapabilities)
                        isNetworkAvailable = checkNetworkCapabilities(networkCapabilities)
                    }

                    override fun onLost(network: Network) {
                        super.onLost(network)
                        val activeNetwork = connectivityManager.activeNetwork
                        if (activeNetwork == null) {
                            isNetworkAvailable = false
                        }
                        val networkCapabilities = connectivityManager.getNetworkCapabilities(activeNetwork)
                        isNetworkAvailable =
                            networkCapabilities != null && checkNetworkCapabilities(networkCapabilities)
                    }
                }
                connectivityManager.registerNetworkCallback(NetworkRequest.Builder().build(), callback)
            }
        }

    }

    private fun checkNetworkCapabilities(networkCapabilities: NetworkCapabilities): Boolean {
        return if (networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)) {
            if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI_AWARE)) {
                Log.d(TAG, "使用 Wifi")
            } else if (networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_MMS) ||
                networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_FOTA)
            ) {
                Log.d(TAG, "使用数据流量")
            } else {
                Log.d(TAG, "使用未知网络")
            }
            true
        } else {
            false
        }
    }


    override fun isNetworkAvailable(): Boolean = isNetworkAvailable

    companion object {
        private const val TAG = "Network"
    }
}
